/**
 * @brief 统一驱动: GPIO 驱动的按钮
 * @author 张勇 41204@qq.com
 * @date 2022-04
 */

#pragma once

#include "mcu.h"
#include "unios.h"

// 按键抖动消除时间(ms)，按下后在此时间内又弹起则视为抖动，不产生事件
#define UNIDRV_BUTTON_JITTER_TIME      50
// 多次点击之间允许的时间间隔(ms)，在此时间内连续点击才会产生多次点击事件
#define UNIDRV_BUTTON_CLICKS_INTERVAL  250
// 按键click时间: 按下时间介于 (UNIDRV_BUTTON_JITTER_TIME, UNIDRV_BUTTON_LONGPRESS_TIME1) 视为click事件
// 按键long press时间(ms)，按下后大于此时间后视为long press1事件
#define UNIDRV_BUTTON_LONGPRESS_TIME1  2000
// 按键long press时间(ms)，按下后大于此时间后视为long press2事件
#define UNIDRV_BUTTON_LONGPRESS_TIME2  15000

/// 按钮状态
typedef enum _unidrv_button_state {
	UNIDRV_BUTTON_UP        	= 0x00,
	UNIDRV_BUTTON_DOWN        	= 0x01,
} unidrv_button_state_t;

/// 按键/旋钮 事件类定义
typedef enum _unidrv_button_event_type {
	UNIDRV_BUTTON_EVENT_UP = 0,			// 按钮弹起
	UNIDRV_BUTTON_EVENT_DOWN,			// 按钮按下
	UNIDRV_BUTTON_EVENT_CLICK,			// 按钮单击
	UNIDRV_BUTTON_EVENT_CLICK2,			// 按钮双击
	UNIDRV_BUTTON_EVENT_CLICK3,			// 按钮三击
	UNIDRV_BUTTON_EVENT_LONG_PRESS1,	// 按钮长按1
	UNIDRV_BUTTON_EVENT_LONG_PRESS2,	// 按钮长按2
	UNIDRV_BUTTON_EVENT_UP_GEAR,		// (有限位)旋钮(按钮保持弹起状态)绝对档位;   extraParams[0]=当前档位    , extraParams[1]=总共有多少档
	UNIDRV_BUTTON_EVENT_UP_FORWARD,		// (无限位)旋钮(按钮保持弹起状态)顺时针旋转; extraParams[0]=旋转了多少档, extraParams[1]=总共有多少档
	UNIDRV_BUTTON_EVENT_UP_BACKWARD,	// (无限位)旋钮(按钮保持弹起状态)逆时针旋转; extraParams[0]=旋转了多少档, extraParams[1]=总共有多少档
	UNIDRV_BUTTON_EVENT_DOWN_GEAR,		// (有限位)旋钮(按钮保持按下状态)绝对档位;   extraParams[0]=当前档位    , extraParams[1]=总共有多少档
	UNIDRV_BUTTON_EVENT_DOWN_FORWARD,	// (无限位)旋钮(按钮保持按下状态)顺时针旋转; extraParams[0]=旋转了多少档, extraParams[1]=总共有多少档
	UNIDRV_BUTTON_EVENT_DOWN_BACKWARD,	// (无限位)旋钮(按钮保持按下状态)逆时针旋转; extraParams[0]=旋转了多少档, extraParams[1]=总共有多少档
} unidrv_button_event_type_t;

// forward declares
typedef struct _unidrv_button unidrv_button_t;

// 按钮事件回调函数 类型
typedef void (*func_button_callback_t)(void *cookie, unidrv_button_t *dev, unidrv_button_event_type_t event);

/// 按钮驱动类
typedef struct _unidrv_button {
	/// 按钮是否按下
	func_gpio_is_in_on_t funcIsDown;
	// Button 事件回调函数
	func_button_callback_t callback; void* callback_cookie;
	/// 轮询任务
	unios_task_t pollTaskId;
	
	/// 按键状态机
	uint8_t lastState;
	/// 按键按下时间
	unios_ms_t keyDownTime;
	/// 上一次点击时间
	unios_ms_t lastClickTime;
	/// 已点击次数
	uint32_t clickTimes;

	bool onDownTriggered;
	bool onLongPress1Triggered;
	bool onLongPress2Triggered;
} unidrv_button_t;

/// @brief 挂接事件回调函数
static inline void unidrv_button_setup_callback(unidrv_button_t* dev, func_button_callback_t callback, void* callback_cookie) {
	if(!dev) return;
	dev->callback = callback; dev->callback_cookie = callback_cookie;
}

/// @brief 获取按钮状态
static inline unidrv_button_state_t unidrv_button_state(unidrv_button_t* dev) {
	if(!dev || !dev->funcIsDown) { return UNIDRV_BUTTON_UP; }
	return (dev->funcIsDown() ? UNIDRV_BUTTON_DOWN : UNIDRV_BUTTON_UP);
}

/// @brief 监听
void unidrv_button_listen(unidrv_button_t* dev, bool enable);
